﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Media.Animation;
using System.Collections.ObjectModel;

namespace System.Windows.Media.Media3D10
{
    /// <summary>
    /// Représente un objectif de caméra
    /// </summary>
    public sealed class Objective : Animatable
    {
        #region DependencyProperties
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="ApertureMask"/>.
        /// </summary>
        public static readonly DependencyProperty ApertureMaskProperty =
            DependencyProperty.Register("ApertureMask", typeof(Brush), typeof(Objective));
        
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="ApertureMask"/>.
        /// </summary>
        public static readonly DependencyProperty LensProperty =
            DependencyProperty.Register("Lens", typeof(LensCollection), typeof(Objective));
        
        /// <summary>
        /// Identifie la propriété de dépendance <see cref="MinZoom"/>.
        /// </summary>
        public static readonly DependencyProperty MinZoomProperty =
            DependencyProperty.Register("MinZoom", typeof(double), typeof(Objective),
            new PropertyMetadata(1.0, new PropertyChangedCallback(MinZoom_PropertyChanged)));

        /// <summary>
        /// Identifie la propriété de dépendance <see cref="MaxZoom"/>.
        /// </summary>
        public static readonly DependencyProperty MaxZoomProperty =
            DependencyProperty.Register("MaxZoom", typeof(double), typeof(Objective),
            new PropertyMetadata(1.0, new PropertyChangedCallback(MaxZoom_PropertyChanged)));

        /// <summary>
        /// Identifie la propriété de dépendance <see cref="FocalZoom"/>.
        /// </summary>
        public static readonly DependencyProperty FocalZoomProperty =
            DependencyProperty.Register("FocalZoom", typeof(double), typeof(Objective),
            new PropertyMetadata(1.0, new PropertyChangedCallback(FocalZoom_PropertyChanged)));
        #endregion

        #region DependencyProperties callbacks
        private static void MinZoom_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(sender, null))
                throw new ArgumentNullException("sender");
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            ((Objective)sender).OnMinZoomChanged(e);
        }

        private static void MaxZoom_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(sender, null))
                throw new ArgumentNullException("sender");
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            ((Objective)sender).OnMaxZoomChanged(e);
        }

        private static void FocalZoom_PropertyChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(sender, null))
                throw new ArgumentNullException("sender");
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
            
            Objective objective = (Objective)sender;
            double focalZoom = (double)e.NewValue;
            
            if (focalZoom > objective.MaxZoom)
            {
                objective.FocalZoom = objective.MaxZoom;
            }
            else if (focalZoom < objective.MinZoom)
            {
                objective.FocalZoom = objective.MaxZoom;
            }
            else
            {
                objective.OnFocalZoomChanged(e);
            }
        }
        #endregion

        #region Constructors
        /// <summary>
        /// Initialise une nouvelle instance de la classe <see cref="Objective"/>
        /// </summary>
        public Objective()
        {
            this.Lens = new LensCollection();
        }
        #endregion

        #region Public Properties
        /// <summary>
        /// Zoom focal minimal de l'objectif
        /// </summary>
        public double MinZoom
        {
            get { return (double)GetValue(MinZoomProperty); }
            set { SetValue(MinZoomProperty, value); }
        }

        /// <summary>
        /// Zoom focal maximal de l'objectif
        /// </summary>
        public double MaxZoom
        {
            get { return (double)GetValue(MaxZoomProperty); }
            set { SetValue(MaxZoomProperty, value); }
        }

        /// <summary>
        /// Zoom focal de l'objectif
        /// </summary>
        public double FocalZoom
        {
            get { return (double)GetValue(FocalZoomProperty); }
            set { SetValue(FocalZoomProperty, value); }
        }

        /// <summary>
        /// <see cref="System.Windows.Media.Brush"/> représentant l'ouverture focale de l'objectif
        /// </summary>
        public Brush ApertureMask
        {
            get { return (Brush)GetValue(ApertureMaskProperty); }
            set { SetValue(ApertureMaskProperty, value); }
        }

        /// <summary>
        /// Liste des lentilles de l'objectif
        /// </summary>
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2227", Justification="Dependency Property")]
        public LensCollection Lens
        {
            get { return (LensCollection)GetValue(LensProperty); }
            set { SetValue(LensProperty, value); }
        }
        #endregion

        #region Public Methods
        /// <summary>
        /// Crée un clone modifiable de ce <see cref="Objective"/>, en créant des copies complètes des valeurs de cet objet.
        /// Lors de la copie de propriétés de dépendance, cette méthode copie les références de ressources et les liaisons de données (même si elles ne peuvent plus être résolues), mais pas les animations ni leurs valeurs actuelles.
        /// </summary>
        /// <returns>
        /// Clone modifiable de l'objet actuel.
        /// La valeur de la propriété <see cref="Freezable.IsFrozen"/> de l'objet cloné est false, même si la valeur de la propriété <see cref="Freezable.IsFrozen"/> de la source est true.
        /// </returns>
        public new Objective Clone()
        {
            return base.Clone() as Objective;
        }

        /// <summary>
        /// Crée un clone modifiable de ce <see cref="Objective"/>, en créant des copies complètes des valeurs actuelles de cet objet.
        /// Contrairement à leurs valeurs actuelles, les références de ressources, les liaisons de données et les animations ne sont pas copiées.
        /// </summary>
        /// <returns>
        /// Clone modifiable de l'objet actuel.
        /// La valeur de la propriété <see cref="Freezable.IsFrozen"/> de l'objet cloné est false, même si la valeur de la propriété <see cref="Freezable.IsFrozen"/> de la source est true.
        /// </returns>
        public new Objective CloneCurrentValue()
        {
            return base.CloneCurrentValue() as Objective;
        }
        #endregion

        #region Private Members
        private void OnFocalZoomChanged(DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
        }

        private void OnMinZoomChanged(DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
        }

        private void OnMaxZoomChanged(DependencyPropertyChangedEventArgs e)
        {
            if (object.ReferenceEquals(e, null))
                throw new ArgumentNullException("e");
        }
        #endregion

        #region Freezable Implementation
        /// <summary>
        /// Une fois implémentée dans une classe dérivée, initialise une nouvelle instance de la classe dérivée <see cref="Freezable"/>. 
        /// </summary>
        /// <returns>Nouvelle instance.</returns>
        protected override Freezable CreateInstanceCore()
        {
            return new Objective();
        }
        #endregion
    }
}
